The development of complex computer programs has led to an increasing dependence by developers on a data storage mechanism known as a stack, so as to avoid the requirement for massive static (or permanent) storage within the computer programs themselves.
Instead of static memory, the programs use dynamic storage in the stack which must be allocated whenever functions or procedures are called. Thus, inactive functions do not use any storage space. The active functions' local data are each stored in a procedure activation record or stack frame, with each variable or data object for the procedure having a unique location within the activation record demarcated by beginning and ending addresses.
The environments for early operating system were in 16-bit code based on collections of memory objects called segments not exceeding 64K bytes in size. However, it was found that 16-bit programs do not deal well with large pieces of data due to the 64K byte limitation. Consequently, the development of 32-bit code that could handle larger programs and was actually easier to program in, resulted in a move towards use of 32-bit coding in new programs.
Despite the migration of the computing environment from 16-bit code to 32-bit code, many existing applications and libraries still exist in 16-bit code only. These tools are often found to be incompatible with the components in 32-bit programs.
One reason for this is the 64K byte accessing limit of 16-bit code routines not found in 32-bit code. For example, in IBM's OS/2, 32-bit addressing is accomplished by creating a very large segment (up to 4 gigabytes in size) in stack memory, and using all near adresses inside this very large segment. The Data and Code segments of any function are mapped to this very large address space, and their limits set to varying sizes up to 4 G, with the possibility, in any variable or data object, such as the stack, or even at the end of the stack last, of easily exceeding the 64K limit applicable to 16-bit applications.
The parameters and local variables allocated in a procedure which calls 16-bit code must not cross any 64K byte boundaries if the 16-bit code routine is to be able to access the parameters and local variables correctly.
Another area of incompatibility between 16 and 32-bit code is the difference in format of the pointers associated with each type of code.
A pointer is a variable containing the address of another variable or data object.
The base linear address for all pointers in 32-bit code is set at zero, and consequently, 32-bit pointers are said to be "flat" or "linear". Pointers in 16-bit code are in the form of a segment number and the offset location of the beginning of the data object within the segment. No provision is made in calculating the values of 16-bit code pointers for a uniform base linear value as in 32-bit code pointers.
The result is that pointers cannot be shared or passed between 16 and 32-bit code without conversion to the other type of pointer. One method of achieving this conversion involves structuring the 64K byte segments contiguously (ie, arranging the 64K byte boundaries consecutively) in the stack as a ranked series of "tiles", the first tile being identified as the "zero" segment, the second as 1, and so on. A simple mathematical conversion of the linear pointers to multiples of 64K, with the remainder representing the offset within the segment, can be then be done. The converted segmented pointers can also be easily re-converted to the 32-bit code format on return of the 16-bit code function.
In the ordinary course of culling from 32-bit code to 16-bit code, a 32-bit program would pass the pointer for a data object to a 16-bit routine. Even in compatible format, if the pointer points to data that spans a 64K boundary, the 16-bit routine will be unable to reference the entire data object, and program implementation will be, at best, unstable, and possibly unworkable.
Generalized solutions have been offered to deal with such matters as the problems raised in a situation where access to an extended address space may be required by systems having different word lengths without the basic addressing system reflecting their physical structure (U.S. Pat. No. 4,493,027--Katz), and memory accesses utilizing different data structures (U.S. Pat. Nos. 5,060,186--Barbagelata, and 4,297,743--Appell).
However, previous solutions to the specific problem of mixed 16/32-bit calls have been limited to providing specialized subroutines, often generated by the compiler each time, to deal individually with each instance of a 16-bit call. In such specialised subroutines, the layout of the parameter list all opportunities for 64K byte boundaries to cause problems in runtime had to be known at compile time. It is not always possible to know at compile time where all these 64K byte boundaries are located on the stack, so that even this solution is limited.